from fastapi import Depends, Form, HTTPException, status
from fastapi.security import OAuth2PasswordBearer
from sqlalchemy.ext.asyncio import AsyncSession
from jwt.exceptions import InvalidTokenError

from . import crud
from . import utils as auth_utils
from scaner.core.models import User, db_helper


oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/v1/auth/login/")


async def validate_auth_user(
    email: str = Form(...),
    password: str = Form(...),
    session: AsyncSession = Depends(db_helper.get_async_session),
) -> User:
    unauthed_exc = HTTPException(
        status_code=status.HTTP_401_UNAUTHORIZED,
        detail="не верные имя или пароль",
    )

    user: User | None = await crud.get_user_by_email(session, email)

    if not user:
        raise unauthed_exc

    if not auth_utils.validate_password(
        password=password,
        hashed_password=user.hashed_password,
    ):
        raise unauthed_exc

    if not user.active:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="пользователь не активирован",
        )

    return user


def get_current_token_payload(
    token: str = Depends(oauth2_scheme),
) -> dict:
    try:
        payload = auth_utils.decode_jwt(token=token)
    except InvalidTokenError as e:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="неверный токен",
        )
    return payload


async def get_current_auth_user(
    payload: dict = Depends(get_current_token_payload),
    session: AsyncSession = Depends(db_helper.get_async_session),
) -> User:
    extracted_id = payload.get("sub")

    if extracted_id:
        user_id: int = extracted_id
    else:
        user_id = 0

    user: User | None = await crud.get_user_by_id(session, user_id)

    if user:
        return user

    raise HTTPException(
        status_code=status.HTTP_401_UNAUTHORIZED,
        detail="неверный токен",
    )


def get_current_active_auth_user(
    user: User = Depends(get_current_auth_user),
):
    if user.active:
        return user
    raise HTTPException(
        status_code=status.HTTP_403_FORBIDDEN,
        detail="пользователь не активирован",
    )


def get_current_superuser(
    user: User = Depends(get_current_active_auth_user),
):
    if user.is_superuser:
        return user
    raise HTTPException(
        status_code=status.HTTP_403_FORBIDDEN,
        detail="нет прав доступа",
    )
